package uz.rt.dicom.data;

import uz.rt.dicom.DicomException;
import uz.rt.dicom.ValueRepresentation;
import uz.rt.dicom.data.element.*;
import uz.rt.dicom.tag.DicomTag;

/**
 * This factory creates an IDataElement based on data provided by a dicom tag and either a value representation or a
 * dicom dictionary. This implements a threadsafe singleton pattern.
 */
public class ElementFactory
{
// -------------------------- STATIC METHODS --------------------------

    /**
     * Get an instance of the element factory class.
     *
     * @return An instance of the element factory class.
     */
    public static ElementFactory getInstance()
    {
        return ElementFactorySingleton.getInstance();
    }

// -------------------------- OTHER METHODS --------------------------

    /**
     * Get an IDataElement based on the value representation that is given.
     *
     * @param tag Dicom tag
     * @param vr  Value representation
     * @return IDataElement contain the properties to store a dicom element.
     * @throws DicomException Thrown if:
     *                        <ul>
     *                        <li>Dicom tag is null</li>
     *                        <li>Value representation is null</li>
     *                        <li>Value representation is not recognized</li>
     *                        </ul>
     */
    public IDataElement getElement(DicomTag tag, ValueRepresentation vr) throws DicomException
    {
        if (tag == null)
            throw new DicomException("Dicom tag is not initialised");
        if (vr == null)
            throw new DicomException("Value representation is not initialised");
        if (vr.equals(ValueRepresentation.ApplicationEntity)) return new ApplicationEntity(tag);
        else if (vr.equals(ValueRepresentation.AgeString)) return new AgeString(tag);
        else if (vr.equals(ValueRepresentation.AttributeTag)) return new AttributeTag(tag);
        else if (vr.equals(ValueRepresentation.CodeString)) return new CodeString(tag);
        else if (vr.equals(ValueRepresentation.Date)) return new Date(tag);
        else if (vr.equals(ValueRepresentation.DateTime)) return new DateTime(tag);
        else if (vr.equals(ValueRepresentation.DecimalString)) return new DecimalString(tag);
        else if (vr.equals(ValueRepresentation.FloatingPointDouble)) return new FloatingPointDouble(tag);
        else if (vr.equals(ValueRepresentation.FloatingPointSingle)) return new FloatingPointSingle(tag);
        else if (vr.equals(ValueRepresentation.IntegerString)) return new IntegerString(tag);
        else if (vr.equals(ValueRepresentation.LongText)) return new LongText(tag);
        else if (vr.equals(ValueRepresentation.LongString)) return new LongString(tag);
        else if (vr.equals(ValueRepresentation.OtherByteString)) return new OtherByteString(tag);
        else if (vr.equals(ValueRepresentation.OtherFloatString)) return new OtherFloatString(tag);
        else if (vr.equals(ValueRepresentation.OtherWordString)) return new OtherWordString(tag);
        else if (vr.equals(ValueRepresentation.PersonName)) return new PersonName(tag);
        else if (vr.equals(ValueRepresentation.SequenceOfItems)) return new Sequence(tag);
        else if (vr.equals(ValueRepresentation.ShortString)) return new ShortString(tag);
        else if (vr.equals(ValueRepresentation.ShortText)) return new ShortText(tag);
        else if (vr.equals(ValueRepresentation.SignedLong)) return new SignedLong(tag);
        else if (vr.equals(ValueRepresentation.SignedShort)) return new SignedShort(tag);
        else if (vr.equals(ValueRepresentation.Time)) return new Time(tag);
        else if (vr.equals(ValueRepresentation.UniqueIdentifier)) return new UniqueIdentifier(tag);
        else if (vr.equals(ValueRepresentation.Unknown)) return new Unknown(tag);
        else if (vr.equals(ValueRepresentation.UnlimitedText)) return new UnlimitedText(tag);
        else if (vr.equals(ValueRepresentation.UnsignedLong)) return new UnsignedLong(tag);
        else if (vr.equals(ValueRepresentation.UnsignedShort)) return new UnsignedShort(tag);
        else throw new DicomException("Unknown value representation, unable to get the corresponding dicom element.");
    }

// -------------------------- INNER CLASSES --------------------------

    /**
     * The Factory singleton class storing a static instance of the ElementFactory class. The creation of the new
     * instance is done in a static part of the code and can only be executed once.
     */
    static class ElementFactorySingleton
    {
        /** Instance of the ElementFactory class */
        static ElementFactory instance;

        static
        {
            instance = new ElementFactory();
        }

        /**
         * Get the instance of the ElementFactory class.
         *
         * @return Instance of the ElementFactory class.
         */
        static ElementFactory getInstance()
        {
            return instance;
        }
    }
}
